package com.zb.kl.util;

import com.zb.kl.common.APIResponse;
import com.zb.kl.common.Const;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Map;


/**
 * @author Answer.AI.L
 * @date 2019-04-09
 */
@Slf4j
@Component
public class OkHttpCli {
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType XML = MediaType.parse("application/xml; charset=utf-8");

    @Autowired
    private OkHttpClient okHttpClient;

    /**
     * get 请求
     * @param url       请求url地址
     * @return string
     * */
    public APIResponse doGet(String url) throws Exception {
        return doGet(url, null, null);
    }


    /**
     * get 请求
     * @param url       请求url地址
     * @param params    请求参数 map
     * @return string
     * */
    public APIResponse doGet(String url, Map<String, String> params) throws Exception {
        return doGet(url, params, null);
    }

    /**
     * get 请求
     * @param url       请求url地址
     * @param headers   请求头字段 {k1, v1 k2, v2, ...}
     * @return string
     * */
    public APIResponse doGet(String url, String[] headers) throws Exception {
        return doGet(url, null, headers);
    }


    /**
     * get 请求
     * @param url       请求url地址
     * @param params    请求参数 map
     * @param headers   请求头字段 {k1, v1 k2, v2, ...}
     * @return string
     * */
    public APIResponse doGet(String url, Map<String, String> params, String[] headers) throws Exception {
        HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                urlBuilder.addQueryParameter(entry.getKey(), entry.getValue());
            }
        }

        Request.Builder requestBuilder = new Request.Builder().url(urlBuilder.build());
        if (headers != null && headers.length % 2 == 0) {
            for (int i = 0; i < headers.length; i += 2) {
                requestBuilder.addHeader(headers[i], headers[i + 1]);
            }
        } else if (headers != null) {
            log.warn("headers's length[{}] is not even.", headers.length);
        }
        Request request = requestBuilder
                .build();
        addExtraHeaders(requestBuilder);
        log.info("do get request and url[{}]", request.url().toString());
        return execute(request);
    }

    /**
     * post 请求
     * @param url       请求url地址
     * @param params    请求参数 map
     * @return string
     */
    public APIResponse doPost(String url, Map<String, String> params) throws Exception {
        FormBody.Builder builder = new FormBody.Builder();

        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
//        Request request = new Request.Builder()
//                .url(url)
//                .post(builder.build())
//                .build();

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(builder.build());
        addExtraHeaders(requestBuilder);
        log.info("do post request and url[{}]", url);

        return execute(requestBuilder.build());
    }


    /**
     * post 请求, 请求数据为 json 的字符串
     * @param url       请求url地址
     * @param json      请求数据, json 字符串
     * @return string
     */
    public APIResponse doPostJson(String url, String json) throws Exception {
        log.info("doPostJson request and url[{}]", url);
        return doPostJson(url, json, null);
    }

    public APIResponse doPostJson(String url, String json, HttpServletRequest request) throws Exception {
        log.info("doPostJson request and url[{}]", url);
        return exectePost(url, json, JSON, request);
    }

    /**
     * post 请求, 请求数据为 xml 的字符串
     * @param url       请求url地址
     * @param xml       请求数据, xml 字符串
     * @return string
     */
    public APIResponse doPostXml(String url, String xml) throws Exception {
        log.info("doPostXml request and url[{}]", url);
        return exectePost(url, xml, XML);
    }

    public APIResponse doPostFile(String url, File file, Map<String, String> params) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        builder.addFormDataPart("file", file.getName(), RequestBody.create(MultipartBody.FORM, file));
        if (params != null && !params.isEmpty()) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.addFormDataPart(entry.getKey(), entry.getValue());
            }
        }
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(builder.build());
        addExtraHeaders(requestBuilder);

        return execute(requestBuilder.build());
    }


    private APIResponse exectePost(String url, String data, MediaType contentType) throws Exception {
        return exectePost(url, data, contentType, null);
    }

    private APIResponse exectePost(String url, String data, MediaType contentType, HttpServletRequest request) throws Exception {
        RequestBody requestBody = RequestBody.create(contentType, data);

        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(requestBody);
        addExtraHeaders(builder, request);
        return execute(builder.build());
    }

    private APIResponse execute(Request request) {
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                //成功时返回0
                return APIResponse.success(response.body().string());
            } else {
                //失败时返回具体code:404,500那些
                return APIResponse.failure(response.code(), response.body().string());
            }
        } catch (Exception e) {
            log.error("网关调用异常,e={}", e);
            return APIResponse.failure(1, e.toString());
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

    private void addExtraHeaders(Request.Builder builder) {
        addExtraHeaders(builder, null);
    }

    private void addExtraHeaders(Request.Builder builder, HttpServletRequest request) {
        if (null != MDC.get("traceId")) {
            builder.addHeader(Const.TRACE_ID, MDC.get("traceId"));
        }
        if (null != MDC.get("abilityCode")) {
            builder.addHeader(Const.ABILITY_CODE, MDC.get("abilityCode"));
        }
        if (null != MDC.get("twinCode")) {
            builder.addHeader(Const.TWIN_CODE, MDC.get("twinCode"));
        }
        if (null != MDC.get("entityCode")) {
            builder.addHeader(Const.ENTITY_CODE, MDC.get("entityCode"));
        }
        if (null != MDC.get("serviceCode")) {
            builder.addHeader(Const.SERVICE_CODE, MDC.get("serviceCode"));
        }
        if (null != request && null != request.getHeader("Debug")) {
            builder.addHeader("Debug", request.getHeader("Debug"));
        }
    }

}
